package cat

import (
	"context"
	"go.uber.org/zap"
	"strconv"
	"strings"
	"wzgames/internal/gloader"
	"wzgames/internal/gvalidator"
	"wzgames/internal/model/dwp"
	"wzgames/internal/model/gamep"
	"wzgames/internal/model/login"
	"wzgames/internal/model/mcomm"
	"wzgames/internal/response"
	"wzgames/pkg/actor/actorservice"
	"wzgames/pkg/logger"
	"wzgames/pkg/utils/calcutil"
)

type CatService struct {
}

func NewCatService() *CatService {
	return &CatService{}
}

// GenID 基于数据库的ID生成
func (sv *CatService) GenID(ctx context.Context, req *mcomm.ID, res *mcomm.IdReply) error {
	res.RetID = gloader.CommMgr().GenID(req.BizID, req.Step)
	return nil
}

// GenSonyFlakeID 基于SonyFlake的ID生成
func (sv *CatService) GenSonyFlakeID(ctx context.Context, req *mcomm.ID, res *mcomm.IdReply) error {
	res.RetID = gloader.GenSonyFlakeID()
	return nil
}

// UserAuth B端玩家登录
func (sv *CatService) UserAuth(ctx context.Context, req *login.UserAuth, res *login.UserAuthReply) error {
	agt := gloader.GetAgent(req.AgtID)
	if agt == nil || !agt.Available() {
		res.Code = int32(response.ErrAgentID)
		logger.Error("[Cat] illegal agent on UserAuth", zap.Int64("AgtId", req.AgtID))
		return nil
	}
	clientIP := gvalidator.FindClientIP(req.ClientIP)
	if !agt.BackIpCheck(clientIP) {
		res.Code = int32(response.ErrForbidden)
		logger.Warn("[Cat] illegal request on UserAuth", zap.Int64("AgtId", req.AgtID), zap.String("ClientIP", req.ClientIP))
		return nil
	}
	var si strings.Builder
	si.WriteString(req.AgtCode)
	si.WriteString(req.AgtUsername)
	si.WriteString(req.AgtUserId)
	si.WriteString(req.BToken)
	si.WriteString(req.Stamp)
	if !agt.CheckSign(si.String(), req.Sign) {
		res.Code = int32(response.ErrSign)
		return nil
	}
	uInfo := UBaseInfo{
		AgtID:       req.AgtID,
		AgtUsername: req.AgtUsername,
		AgtUserId:   req.AgtUserId,
	}
	uh, uid, code := passport.CheckAccount(agt, uInfo) // 检查或创建账户
	if code == 0 {
		// token 生成
		token, e := passport.GenTicket(uh, req.BToken, agt.AgtId(), uid)
		if e != nil {
			res.Code = int32(response.ErrInternal)
			return nil
		}
		res.Token = token
		// 登录日志
		actorservice.Send(Actor().GetPID(), UserLogin{Uid: uid, NodeId: req.NodeId, Info: uInfo, ClientIP: clientIP})
		return nil
	}
	res.Code = int32(code)
	return nil
}

// DepWitAuth B端玩家转账身份验证，只双钱包
func (sv *CatService) DepWitAuth(ctx context.Context, req *dwp.DepWit, res *dwp.DepWitAuthReply) error {
	agt := gloader.GetAgent(req.AgtID)
	if agt == nil || !agt.Available() {
		res.Code = int32(response.ErrAgentID)
		logger.Error("[Cat] illegal agent on DepWitAuth", zap.Int64("AgtId", req.AgtID))
		return nil
	}
	clientIP := gvalidator.FindClientIP(req.ClientIP)
	if !agt.BackIpCheck(clientIP) {
		res.Code = int32(response.ErrForbidden)
		logger.Warn("[Cat] illegal request on DepWitAuth", zap.Int64("AgtId", req.AgtID), zap.String("ClientIP", req.ClientIP))
		return nil
	}
	if agt.WalletType() != mcomm.WalletType_DouWallet {
		res.Code = int32(response.ErrWalletType)
		return nil
	}
	var si strings.Builder
	si.WriteString(req.AgtCode)
	si.WriteString(req.AgtUsername)
	si.WriteString(req.AgtUserId)
	si.WriteString(req.Amount)
	si.WriteString(req.AgtOrderId)
	si.WriteString(req.ACurrency)
	si.WriteString(req.Stamp)
	if !agt.CheckSign(si.String(), req.Sign) {
		res.Code = int32(response.ErrSign)
		return nil
	}
	curr := agt.GetCurrency(req.ACurrency)
	if curr == nil { // 判断B端是否开放货币支持
		res.Code = int32(response.ErrCurrency)
		return nil
	}
	// 检查转账金额的精度是否满足设定
	if !calcutil.CheckAmountDecimalPoint(req.Amount, curr.Precision) {
		res.Code = int32(response.ErrAmount)
		return nil
	}
	uInfo := UBaseInfo{
		AgtID:       req.AgtID,
		AgtUsername: req.AgtUsername,
		AgtUserId:   req.AgtUserId,
	}
	_, uid, code := passport.CheckAccount(agt, uInfo) // 检查或创建账户
	if code == 0 {
		res.Code = 0
		res.AgtID = agt.AgtId()
		res.Uid = uid
		res.Curr = curr.Curr
		res.CurrID = curr.CurrID
		res.Amount = req.Amount
		res.AgtOrderId = req.AgtOrderId
		res.Uname = req.AgtUsername
		res.ClientIP = clientIP
		res.AgtUid = req.AgtUserId
		return nil
	}

	res.Code = int32(code)
	return nil
}

// BalanceAuth B端玩家余额查询身份验证，只双钱包
func (sv *CatService) BalanceAuth(ctx context.Context, req *dwp.BalanceAuth, res *dwp.BalanceAuthReply) error {
	agt := gloader.GetAgent(req.AgtID)
	if agt == nil || !agt.Available() {
		res.Code = int32(response.ErrAgentID)
		logger.Error("[Cat] illegal agent on BalanceAuth", zap.Int64("AgtId", req.AgtID))
		return nil
	}
	if agt.WalletType() != mcomm.WalletType_DouWallet {
		res.Code = int32(response.ErrWalletType)
		return nil
	}
	var si strings.Builder
	si.WriteString(req.AgtCode)
	si.WriteString(req.AgtUsername)
	si.WriteString(req.AgtUserId)
	si.WriteString(req.ACurrency)
	si.WriteString(req.Stamp)
	if !agt.CheckSign(si.String(), req.Sign) {
		res.Code = int32(response.ErrSign)
		return nil
	}
	curr := agt.GetCurrency(req.ACurrency)
	if curr == nil {
		res.Code = int32(response.ErrCurrency)
		return nil
	}
	uInfo := UBaseInfo{
		AgtID:       req.AgtID,
		AgtUsername: req.AgtUsername,
		AgtUserId:   req.AgtUserId,
	}
	uid, code := passport.CheckAccountExists(agt, uInfo)
	if code == 0 {
		res.Code = 0
		res.AgtID = agt.AgtId()
		res.Uid = uid
		res.Curr = curr.Curr
		res.CurrID = curr.CurrID
		res.Uname = req.AgtUsername
		res.ClientIP = req.ClientIP
		res.UserExists = true
		res.AgtUid = req.AgtUserId
		return nil
	} else if code == response.ErrNotFound { // user not exists
		res.Code = 0
		res.UserExists = false
		return nil
	}

	res.Code = int32(code)
	return nil
}

// WsLoginAuth 游戏客户端WebSocket模式登录验证
func (sv *CatService) WsLoginAuth(ctx context.Context, req *login.WsLogin, res *login.WsLoginReply) error {
	// 判断系统游戏是否支持对应的语言
	if !gloader.GameMgr().CheckSysGameAndLang(req.GameID, req.Lang) {
		res.Code = int32(response.ErrBadRequest)
		return nil
	}
	// 验证客户端的Ticket
	uCache, guest, bToken, code := passport.CheckTicket(req.Token, req.SessionToken)
	if code != 0 {
		res.Code = int32(code)
		return nil
	}
	//if uCache.Uname != req.Un {
	//	res.Code = int32(response.ErrUsername)
	//	return nil
	//}

	agt := gloader.GetAgent(uCache.AgtId)
	if agt == nil || !agt.Available() {
		res.Code = int32(response.ErrAgentID)
		logger.Error("[Cat] illegal agent on WsLoginAuth", zap.Int64("AgtId", uCache.AgtId))
		return nil
	}
	// 判断登录的游戏实例对应的币种方案
	newGcId, currId, precision, code1 := agt.CheckInstAndCurrency(req.GameInstId, req.Currency)
	if code1 != 0 {
		res.Code = int32(code1)
		return nil
	}
	// TODO 记录玩家登录了哪个节点的游戏实例到Cache
	res.LastLoginNodeId = passport.UpdateInstLoginNode(uCache.Uid, req.GameInstId, req.LoginNodeId)
	res.GcId = newGcId
	res.UserCache = uCache
	res.AgtKey = agt.AgtKey()
	res.WalletType = agt.WalletType()
	res.Guest = guest
	res.BToken = bToken
	res.CurrId = currId
	res.Precision = precision

	if !guest {
		// 游戏登录日志
		actorservice.Send(Actor().GetPID(), WsLogin{
			Info:       uCache,
			CurrId:     currId,
			NodeId:     req.LoginNodeId,
			InstId:     req.GameInstId,
			GameId:     req.GameID,
			ClientIP:   gvalidator.FindClientIP(req.ClientIP),
			DeviceType: req.DeviceType,
			DeviceInfo: req.DeviceInfo,
		})
	}

	return nil
}

// GuestGen 游客ticket生成
func (sv *CatService) GuestGen(ctx context.Context, req *login.GuestReq, res *login.GuestReply) error {
	agt := gloader.GetAgent(req.AgtID)
	if agt == nil || !agt.Available() {
		res.Code = int32(response.ErrAgentID)
		logger.Error("[Cat] illegal agent on GuestGen", zap.Int64("AgtId", req.AgtID))
		return nil
	}
	uid := passport.GenUser()
	if uid == 0 {
		res.Code = int32(response.ErrInternal)
		return nil
	}
	uname := strconv.FormatUint(uid, 10)
	// 生成游客的ticket
	token, e := passport.GenGuestTicket(req.AgtID, uid, uname)
	if e != nil {
		res.Code = int32(response.ErrInternal)
		return nil
	}
	res.Token = token
	res.Username = uname
	res.UserId = uid

	return nil
}

// NormalSignAuth 常规请求数据的签名验证
func (sv *CatService) NormalSignAuth(ctx context.Context, req *mcomm.NormalSignCheck, res *mcomm.CodeRet) error {
	agt := gloader.GetAgent(req.AgtID)
	if agt == nil || !agt.Available() {
		res.Code = int32(response.ErrAgentID)
		logger.Error("[Cat] illegal agent on DwCheckAuth", zap.Int64("AgtId", req.AgtID))
		return nil
	}
	if agt.WalletType() != mcomm.WalletType_DouWallet {
		res.Code = int32(response.ErrWalletType)
		return nil
	}
	if !agt.CheckSign(req.Combine, req.Sign) {
		res.Code = int32(response.ErrSign)
		return nil
	}
	if req.ACurrency != "" {
		curr := agt.GetCurrency(req.ACurrency)
		if curr == nil {
			res.Code = int32(response.ErrCurrency)
			return nil
		}
	}
	res.Code = 0
	return nil
}

// GetGameCurrency 获取游戏的币种方案
func (sv *CatService) GetGameCurrency(ctx context.Context, req *mcomm.ID, res *gamep.GameCurrReply) error {
	ret, code := passport.GetGameCurrency(req.BizID)
	res.Code = int32(code)
	if code == 0 {
		res.GameCurr = ret
	}
	return nil
}

// NodeBootHistory 记录应用节点的启动日志
func (sv *CatService) NodeBootHistory(ctx context.Context, req *mcomm.SysNodeBoot, res *mcomm.CodeRet) error {
	passport.CreateNodeBootHistory(req)
	return nil
}
